<?php

namespace mini;

class App
{
    // protected $current_module     = DEFAULT_MODULE;
    // protected $current_controller = DEFAULT_CONTROLLER;
    // protected $current_method     = DEFAULT_METHOD;
    // protected $current_value      = '';

    public function __construct()
    {
        // 内存及运行时间起始记录
        define('START_MEMORY',  memory_get_usage());
        define('START_TIME',  microtime(true));
        // 项目根目录
        define('ROOT_PATH', str_replace("\\", "/", dirname(__DIR__, 4) . '/'));
        // 应用目录
        !defined('APP_PATH') AND define('APP_PATH', ROOT_PATH . 'app/');
        // 请求类型
        define('REQUEST_TYPE', strtoupper($_SERVER['REQUEST_METHOD']));

        $data = $this->get_segments();
        define('SEGMENTS', $data['segments']);
        define('ASSUMED_URL', $data['assumed_url']);

        Session::start();

        // 检查并初始化配置
        $this->init_config();

        // 设置中国时区
        date_default_timezone_set(config('timezone'));

        // 设置调试模式
        if (config('debug')) {
            // 显示错误
            error_reporting(E_ALL);
            ini_set('display_errors', '1');
        } else {
            // 关闭所有错误
            error_reporting(0);
            ini_set('display_errors', '0');
        }

        // 自定义异常
        set_error_handler('\mini\App::error_handler');
        set_exception_handler('\mini\App::exception_handler');

        // 解析路由和应用中的资源文件
        if (strpos(ASSUMED_URL, MODULE_ASSETS_TRIGGER) === false) {
            $this->route();
        } else {
            $this->serve_app_asset();
        }

        // 开启调试追踪
        if (config('trace')) {
            include __DIR__.'/templates/trace.php';
        }
    }

    /**
     * 初始化配置文件
     */
    private function init_config()
    {
        $config_file = APP_PATH . 'config.php';

        if(is_file($config_file)) {
            return true;
        }

        try {
            file_put_contents($config_file, file_get_contents(__DIR__.'/support/config.php'));
        } catch (\Exception $e) {
            // 在这里处理异常，例如你可以记录错误信息，或者返回一个错误响应
            throw new \Exception('写入配置文件时出错');
        }

        return true;
    }

    /**
     * 路由解析
     */
    private function route()
    {
        $url = $this->split_url();

        $module_name     = $url[0];  // 将 url 第一段设置为模块
        $controller_name = $url[0];  // 控制器名与方法名相同
        $method_name     = $url[1];  // 将 url 第二段设置为方法

        $controller_file = ROOT_PATH . 'app/' . $module_name . '/controllers/' . ucfirst($controller_name) . '.php';

        // 控制器不存在，启动 404 页面
        if (!is_file($controller_file)) {
            return page_not_found();
        }

        // 引入类文件，创建类实例
        $controller_name = "\\app\\" . $module_name . "\\controllers\\" . ucfirst($module_name);

        // 如果不使用 composer 则需要手动加载文件
        // require $controller_file;
        $controller = new $controller_name;

        // 定义模块、控制器常量
        define('MODULE_NAME', $module_name);
        define('CONTROLLER_NAME', $controller_name);

        if(!method_exists($controller, $method_name)) {
            $method_name  = config('default_method');
        }

        // 定义方法名、服务器根目录常量
        define('METHOD_NAME', $method_name);
        define('SERVER_ROOT', str_replace('public/index.php', '', $_SERVER['PHP_SELF']));

        // 用于运行追踪
        $GLOBALS['traceSql'] = [];

        define('FRAME_URL', implode('/', $url));

        // 如果对应方法名不存在，启动 404 页面
        if (method_exists($controller, $method_name)) {
            call_user_func([$controller, $method_name]);
        } else {
            return page_not_found();
        }
    }

    /**
     * 解析路由中的资源文件
     */
    private function serve_app_asset() {

        $url_segments = SEGMENTS;

        foreach ($url_segments as $url_segment_key => $url_segment_value) {
            $pos = strpos($url_segment_value, MODULE_ASSETS_TRIGGER);

            if (is_numeric($pos)) {
                $target_module = str_replace(MODULE_ASSETS_TRIGGER, '', $url_segment_value);
                $file_name = $url_segments[count($url_segments)-1];

                $target_dir = '';
                for ($i=$url_segment_key+1; $i < count($url_segments)-1; $i++) {
                    $target_dir.= $url_segments[$i];
                    if ($i<count($url_segments)-2) {
                        $target_dir.= '/';
                    }
                }

                $asset_path = APP_PATH.strtolower($target_module).'/assets/'.$target_dir.'/'.$file_name;

                if (file_exists($asset_path)) {
                    $content_type = mime_content_type($asset_path);

                    if ($content_type === 'text/plain' || $content_type === 'text/html') {

                        $pos2 = strpos($file_name, '.css');
                        if (is_numeric($pos2)) {
                            $content_type = 'text/css';
                        }

                        $pos2 = strpos($file_name, '.js');
                        if (is_numeric($pos2)) {
                            $content_type = 'text/javascript';
                        }

                    }

                    if ($content_type === 'image/svg') {
                        $content_type.= '+xml';
                    }

                    // 确保不是 PHP 文件或 api.json
                    if((is_numeric(strpos($content_type, 'php'))) || ($file_name === 'api.json')) {
                        http_response_code(422);
                        die();
                    }

                    header('Content-type: '.$content_type);
                    $contents = file_get_contents($asset_path);
                    echo $contents;
                    die();
                }
            }
        }

    }

    /**
     * 获取并拆分 URL
     */
    private function get_segments()
    {
        $assumed_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] .  $_SERVER['REQUEST_URI'];

        $data['assumed_url'] = $assumed_url;
    
        $assumed_url = str_replace('://', '/', $assumed_url);
        $assumed_url = rtrim($assumed_url, '/');
    
        $segments = explode('/', $assumed_url);
    
        for ($i=0; $i < $num_segments_to_ditch; $i++) {
            unset($segments[$i]);
        }
    
        $data['segments'] = array_values($segments);

        return $data;
    }

    /**
     * 获取并拆分 URL
     */
    private function split_url()
    {
        if (isset($_GET['url'])) {
            $url = trim($_GET['url'], '/');
            $url = filter_var($url, FILTER_SANITIZE_URL);
            unset($_GET['url']);
        } else {
            $url = config('default_module') . '/' . config('default_controller') . '/' . config('default_method');
        }

        $router = explode('/', $url);

        if (empty($router[0])) {
            array_shift($router);
        }

        /**
         * 自定义路由
         */
        if (config('route')) {
            $routes = require(ROOT_PATH . 'app/routes.php');
            if (array_key_exists($router[0], $routes)) {
                $newRouter    = [];
                $newRouter[0] = $routes[$router[0]][0];
                $newRouter[1] = $routes[$router[0]][1];

                if (!empty($newRouter[2]) && is_array($newRouter[2])) {
                    $newRouter = $newRouter + $newRouter[2];
                }

                define("PAGE_NUMBER",  1);
                return $newRouter;
            };
        }

        $router[0] = isset($router[0]) ? $router[0] : config('default_module');
        $router[1] = isset($router[1]) ? $router[1] : config('default_method');

        for ($i = 2; $i < count($router); $i++) {
            if (preg_match('/^page_(.*)()*$/Ui', $router[$i], $matches)) {
                define("PAGE_NUMBER",  intval($matches[1]));
                array_splice($router, $i, 1);
            }
        }

        if (!defined("PAGE_NUMBER")) {
            define("PAGE_NUMBER",  1);
        }

        return $router;
    }

    /**
     * 设置用户自定义的错误处理程序，然后触发错误。
     *
     * @param int    $code     错误编码
     * @param string $message  错误消息
     * @param string $file     引发错误的文件名
     * @param int    $line     引发错误所在行
     *
     * @return void
     */
    public static function error_handler($level, $message, $file = '', $line): void
    {
        if (error_reporting() !== 0) {
            throw new \ErrorException($message, 0, $level, $file, $line);
        }
    }

    /**
     * 异常处理
     *
     * @param Exception $exception  异常
     *
     * @return void
     */
    public static function exception_handler($exception)
    {
        // Code is 404 (not found) or 500 (general error)
        $code = $exception->getCode();
        if ($code != 404) {
            $code = 500;
        }
        http_response_code($code);

        if (config('debug')) {
            include __DIR__.'/templates/debug.php';
        } else {
            $log = new Log();
            $log->debug($exception->getMessage() . '\n' . $exception->getFile() . '\n' . $exception->getLine());
            return $code;
        }
    }
}
